﻿using MusicExplorer.Data;
using MusicExplorer.WebRepository.Interface;
using MusicExplorer.WebRepository.Service;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Threading;
using System.Text.RegularExpressions;
using System.Web;

namespace MusicExplorer.WebRepository
{
    public class YoutubeWebRepository : WebRepositoryBase,
        IGroupTrackListingWebRepository, IGroupFilterWebRepository
    {
        private static string m_xml_namespace = "http://www.w3.org/2005/Atom";
        private static string m_url_PLAYLISTFEED = "http://gdata.youtube.com/feeds/api/users/{0}/playlists";
        private const string m_url_TRACKS = "http://gdata.youtube.com/feeds/api/playlists/{0}?start-index={1}&max-results={2}&orderby=position";
        private static string m_url_UPLOADTRACKS = "https://gdata.youtube.com/feeds/api/users/{0}/uploads?start-index={1}&max-results={2}&orderby=published";

        public YoutubeWebRepository(string channelId)
        {
            m_web_repository = ServiceWebRepository.GetYoutubeWebRepository(channelId);
            m_result_per_page = 10;
        }

        #region TRACKS

        public async Task<List<TRACK>> GetTracksFromGroupAsync(WebClient webClient, CancellationToken token, GROUP group, int page)
        {
            if (group.group_key == m_web_repository.web_repo_key + "_uploaded_videos")
            {
                var xmlTracks = await ServiceWebRepository.GetUrlDataAsync(webClient, string.Format(m_url_UPLOADTRACKS, m_web_repository.web_repo_key, 1 + (page - 1) * m_result_per_page, m_result_per_page));
                return GetTracks(group, xmlTracks);
            }
            else
            {
                var xmlTracks = await ServiceWebRepository.GetUrlDataAsync(webClient, string.Format(m_url_TRACKS, group.group_key, 1 + (page - 1) * m_result_per_page, m_result_per_page));
                return GetTracks(group, xmlTracks);
            }
        }

        private List<TRACK> GetTracks(GROUP group, string xmlTracks)
        {
            var tracks = new List<TRACK>();
            XDocument doc = XDocument.Parse(xmlTracks);
            XNamespace nmsp = m_xml_namespace;
            XNamespace media = "http://search.yahoo.com/mrss/";
            XNamespace yt = "http://gdata.youtube.com/schemas/2007";
            var tracksElement = doc.Root.Elements(nmsp + "entry");

            foreach (var t in tracksElement)
            {
                var mediaXml = t.Element(media + "group");
                var thumbnail = mediaXml.Element(media + "thumbnail");
                var link = t.Elements(nmsp + "link").First(e => e.Attribute("rel").Value == "alternate");
                var track = new TRACK()
                {
                    track_name = HttpUtility.HtmlDecode(t.Element(nmsp + "title").Value),
                    group_key = group.group_key,
                    web_repo_id = m_web_repository.web_repo_id,
                    track_mp3_url = link.Attribute("href").Value.Split(',').First().Replace("&feature=youtube_gdata", ""),
                    track_img_url = thumbnail.Attribute("url").Value,
                    track_publish_date = DateTime.Parse(t.Element(nmsp + "published").Value),
                    track_duration = Int32.Parse(mediaXml.Element(yt + "duration").Attribute("seconds").Value)
                };

                track.track_key = Regex.Split(track.track_mp3_url, "v=").Last();

                ServiceWebRepository.InsertOrUpdateTrack(track);

                tracks.Add(track);
            }
            return tracks;
        }

        #endregion

        #region GROUPS

        public async Task<List<GROUP>> GetGroupsAsync(WebClient webClient, CancellationToken token)
        {
            token.ThrowIfCancellationRequested();
            var xmlUser = await ServiceWebRepository.GetUrlDataAsync(webClient, string.Format(m_url_PLAYLISTFEED, m_web_repository.web_repo_key));
            token.ThrowIfCancellationRequested();
            return GetGroups(xmlUser, token);
        }

        private List<GROUP> GetGroups(string xmlUser, CancellationToken token)
        {
            var groups = new List<GROUP>();

            var uploadGroup = new GROUP()
            {
                group_key = m_web_repository.web_repo_key + "_uploaded_videos",
                group_name = "All uploaded videos",
                web_repo_id = m_web_repository.web_repo_id
            };

            uploadGroup = ServiceWebRepository.InsertOrUpdateGroup(uploadGroup);
            groups.Add(uploadGroup);

            XDocument doc = XDocument.Parse(xmlUser);
            XNamespace nmsp = m_xml_namespace;
            var playlists = doc.Root.Elements(nmsp + "entry");

            foreach (var p in playlists.OrderByDescending(p => DateTime.Parse(p.Element(nmsp + "published").Value)))
            {
                var group = new GROUP()
                {
                    group_key = p.Element(nmsp + "id").Value.Split('/').Last(),
                    group_name = HttpUtility.HtmlDecode(p.Element(nmsp + "title").Value),
                    web_repo_id = m_web_repository.web_repo_id
                };

                group = ServiceWebRepository.InsertOrUpdateGroup(group);

                groups.Add(group);

                token.ThrowIfCancellationRequested();
            }
            return groups;
        }

        #endregion
    }
}
